package com.ls.fw.search.lucene.bean;

import java.math.BigDecimal;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Date;

import org.apache.lucene.analysis.TokenStream;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.DoublePoint;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.FieldType;
import org.apache.lucene.document.LongPoint;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.StringField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexOptions;
import org.apache.lucene.index.IndexableField;

/**
 * 对单一文档进行操作的类
 * 
 * @author lisheng
 * @date 2015年1月19日 下午8:37:46
 * @version V1.0
 */
public class DocBuilder {
    
	protected Document doc = new Document();

    public DocBuilder() {
    }

    public static boolean isDouble(Number value) {
        if (value.getClass().equals(Float.class) || value.getClass().equals(Double.class)
                || value.getClass().equals(BigDecimal.class)) {
            return true;
        }
        return false;
    }

    /**
     * 以参数type来决定索引、保存的方式
     * @param propName
     * @param value
     * @param type
     */
    public DocBuilder add(String propName, String value, FieldType type) {
        if (value == null) {
            return this;
        }
        this.doc.add(new Field(propName, value, type));
        return this;
    }

    /**
     * 索引且保存字符串
     * @param propName
     * @param value
     */
    public DocBuilder add(String propName, String value) {
        if (value == null) {
        	return this;
        }
        this.doc.add(new StringField(propName, value, Field.Store.YES));
        return this;
    }

    /**
     * 索引且保存字符串
     * @param propName
     * @param value
     */
    public DocBuilder addString(String propName, String value, boolean tokenized) {
        if (value == null) {
        	return this;
        }
        FieldType type = new FieldType();
        type.setOmitNorms(true);
        type.setIndexOptions(org.apache.lucene.index.IndexOptions.DOCS);
        type.setStored(true);
        type.setTokenized(tokenized);
        type.freeze();
        this.doc.add(new Field(propName, value, type));
        return this;
    }

    /**
     * 索引且保存数字
     * @param propName
     * @param value
     */
    public DocBuilder add(String propName, Number value) {
        if (value == null) {
        	return this;
        }
        if (isDouble(value)) {
            this.doc.add(new DoublePoint(propName, value.doubleValue()));
        } else {
            this.doc.add(new LongPoint(propName, value.longValue()));
        }
        return this;
    }

    /**
     * 索引且保存日期
     * @param propName
     * @param value
     */
    public DocBuilder add(String propName, Date value) {
        if (value == null) {
        	return this;
        }
        this.doc.add(new LongPoint(propName, value.getTime()));
        return this;
    }

    /**
     * 索引但不保存字符串
     * @param propName
     * @param value
     */
    public DocBuilder index(String propName, String value) {
        if (value == null) {
        	return this;
        }
        this.doc.add(new StringField(propName, value, Field.Store.NO));
        return this;
    }

    /**
     * 索引但不保存字符串
     * @param propName
     * @param value
     */
    public DocBuilder index(String propName, String value, boolean tokenized) {
        if (value == null) {
        	return this;
        }
        FieldType index = new FieldType();
        index.setOmitNorms(true);
        index.setIndexOptions(IndexOptions.DOCS);
        index.setTokenized(tokenized);
        index.freeze();
        this.doc.add(new Field(propName, value, index));
        return this;
    }

    /**
     * 索引但不保存数字
     * @param propName
     * @param value
     */
    public DocBuilder index(String propName, Number value) {
        if (value == null) {
        	return this;
        }
        if (isDouble(value)) {
            this.doc.add(new DoublePoint(propName, value.doubleValue()));
        } else {
            this.doc.add(new LongPoint(propName, value.longValue()));
        }
        return this;
    }

    /**
     * 索引但不保存日期
     * @param propName
     * @param value
     */
    public DocBuilder index(String propName, Date value) {
        if (value == null) {
        	return this;
        }
        this.doc.add(new LongPoint(propName, value.getTime()));
        return this;
    }

    /**
     * 不索引但保存字符串
     * @param propName
     * @param value
     */
    public DocBuilder store(String propName, String value) {
        FieldType type = new FieldType();
        type.setOmitNorms(true);
        type.setIndexOptions(IndexOptions.DOCS);
        type.setStored(true);
        type.setTokenized(false);
        type.freeze();
        add(propName, value, type);
        return this;
    }

    public DocBuilder addField(IndexableField field) {
        getDocument().add(field);
        return this;
    }

    public DocBuilder add(final String name, final Timestamp value
			, final FieldType fieldType){
		Field f = null;
		long v = (value==null ? 0L : value.getTime());
		f = new LongPoint(name, v);
		if(fieldType.stored()){
			this.addField(new StoredField(name, v));
		}
		return this.addField(f);
	}
	
	public DocBuilder add(final String name, final Date value
			, final FieldType fieldType){
		Field f = null;
		long v = (value==null ? 0L : value.getTime());
		f = new LongPoint(name, v);
		if(fieldType.stored()){
			this.addField(new StoredField(name, v));
		}
		return this.addField(f);
	}
	
	public DocBuilder add(final String name, final Time value
			, final FieldType fieldType){
		Field f = null;
		long v = (value==null ? 0L : value.getTime());
		f = new LongPoint(name, v);
		if(fieldType.stored()){
			this.addField(new StoredField(name, v));
		}
		return this.addField(f);
	}
	
	
	public DocBuilder add(final String name, final Timestamp value
			, final boolean store){
		Field f = null;
		long v = (value==null ? 0L : value.getTime());
		f = new LongPoint(name, v);
		if(store){
			this.addField(new StoredField(name, v));
		}
		return this.addField(f);
	}
	
	public DocBuilder add(final String name, final Date value
			, final boolean store){
		Field f = null;
		long v = (value==null ? 0L : value.getTime());
		f = new LongPoint(name, v);
		if(store){
			this.addField(new StoredField(name, v));
		}
		return this.addField(f);
	}
	
	
	public DocBuilder add(final String name, final String value
			, final boolean store, final boolean token){
		Field f = null;
		String v = (value==null ? "" : value);
		if(token){
			f = new TextField(name, v, store?Field.Store.YES:Field.Store.NO);
		}else{
			f = new StringField(name, v, store?Field.Store.YES:Field.Store.NO);
		}
		return this.addField(f);
	}
	
	
	/**
	 * 分词
	 * @author ls
	 * 2015-1-23下午04:40:32
	 * @param name
	 * @param value
	 * @param store
	 * @return
	 */
	public DocBuilder add(final String name, final String value
			, final boolean store){
		Field f = null;
		String v = (value==null ? "" : value);
		f = new TextField(name, v, store?Field.Store.YES:Field.Store.NO);
		return this.addField(f);
	}
	
	
	public DocBuilder add(final String name, final TokenStream  tokenStream
			, final boolean store){
		Field f = null;
		f = new TextField(name, "", store?Field.Store.YES:Field.Store.NO);
		f.setTokenStream(tokenStream);
		return this.addField(f);
	}
	
    public Document getDocument() {
        return this.doc;
    }
}
